From 34f9c21aa96f0660d126c428b6f58654556a5148 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Mon, 20 Feb 2023 08:05:24 -0700 Subject: [PATCH] add support for dynamic formats (#1005) * de-duplicate format setup in find_vec * create a class to pass format info pack and forth from vecs. This simplifies re-initialization of a format, which main already did in a few cases. The operator overloads for the format info class make the transition simplier. * return empty braced init list from find_vecs when not found. * dynamic format checkpoint. * delete static GeoFormat instance. * support dynamic xcsv format. allow dynamic formats to use rd_init, rd_deinit, wr_init, wr_denint. This makes conversion to dynamic formats easier as we can, but aren't forced to move the old init/deinit code. Often rd/wr_init is intertwined with rd/wr_posn_init. use dynamic xcsv format. fix undiscovered bug releated to option order. We assumed an order of -i -f -o -F, but -i -o -f -F can cause errors if both formats are style based. test for above bug added to iblue747.test. * add missing reference * use template for format factories. * correct vecs includes * fix another filename parameter for positional args issue. * make Vecs::prepare_format static. * move prepare_format call to just before xxx_init for both static and dynamic formats. --- format.h | 3 + garmin.cc | 8 +- geo.cc | 24 +- geo.h | 11 +- main.cc | 99 +++- reference/track/iblue747~csv.csv | 747 +++++++++++++++++++++++++++++++ testo.d/geo.test | 5 + testo.d/iblue747.test | 3 + vecs.cc | 110 +++-- vecs.h | 24 +- xcsv.h | 1 + 11 files changed, 940 insertions(+), 95 deletions(-) create mode 100644 reference/track/iblue747~csv.csv diff --git a/format.h b/format.h index 44ef80813..01e887b82 100644 --- a/format.h +++ b/format.h @@ -45,6 +45,7 @@ class Format { public: Format() = default; + Format(const QString& filename) : fname{filename} {} // Provide virtual public destructor to avoid undefined behavior when // an object of derived class type is deleted through a pointer to // its base class type. @@ -169,6 +170,8 @@ public: virtual ff_type get_type() const = 0; virtual QVector get_cap() const = 0; + QString fname; + protected: template class RteHdFunctor diff --git a/garmin.cc b/garmin.cc index 59db848ef..fb9a8cdae 100644 --- a/garmin.cc +++ b/garmin.cc @@ -81,7 +81,7 @@ static int categorybits; static int receiver_must_upper = 1; static QTextCodec* codec{nullptr}; -static Format* gpx_vec; +static Vecs::fmtinfo_t gpx_vec; #define MILITANT_VALID_WAYPT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" @@ -355,10 +355,12 @@ rd_init(const QString& fname) { if (setjmp(gdx_jmp_buf)) { const gdx_info* gi = gdx_get_info(); - gpx_vec = Vecs::Instance().find_vec("gpx").fmt; + // FIXME: dynamic not implemented. + gpx_vec = Vecs::Instance().find_vec("gpx"); + Vecs::prepare_format(gpx_vec); gpx_vec->rd_init(gi->from_device.canon); } else { - gpx_vec = nullptr; + gpx_vec = Vecs::fmtinfo_t(); rw_init(fname); } } diff --git a/geo.cc b/geo.cc index 37dd6c627..808a96121 100644 --- a/geo.cc +++ b/geo.cc @@ -84,19 +84,9 @@ void GeoFormat::GeoReadLoc(QXmlStreamReader& reader) const } } -void GeoFormat::rd_init(const QString& fname) -{ - geo_fname = fname; -} - -void GeoFormat::rd_deinit() -{ - geo_fname.clear(); -} - void GeoFormat::read() { - gpsbabel::File ifile = gpsbabel::File(geo_fname); + gpsbabel::File ifile = gpsbabel::File(fname); ifile.open(QIODevice::ReadOnly); QXmlStreamReader reader = QXmlStreamReader(&ifile); @@ -143,16 +133,6 @@ Geocache::container_t GeoFormat::wpt_container(const QString& args) return v; } -void GeoFormat::wr_init(const QString& fname) -{ - geo_fname = fname; -} - -void GeoFormat::wr_deinit() -{ - geo_fname.clear(); -} - void GeoFormat::geo_waypt_pr(const Waypoint* waypointp, QXmlStreamWriter& writer) { writer.writeStartElement(QStringLiteral("waypoint")); @@ -221,7 +201,7 @@ void GeoFormat::geo_waypt_pr(const Waypoint* waypointp, QXmlStreamWriter& writer void GeoFormat::write() { - gpsbabel::File ofile = gpsbabel::File(geo_fname); + gpsbabel::File ofile = gpsbabel::File(fname); ofile.open(QIODevice::WriteOnly | QIODevice::Text); QXmlStreamWriter writer = QXmlStreamWriter(&ofile); diff --git a/geo.h b/geo.h index 8545c6c10..884b47cdd 100644 --- a/geo.h +++ b/geo.h @@ -32,6 +32,8 @@ class GeoFormat : public Format { public: + using Format::Format; + QVector* get_args() override { return &geo_args; @@ -47,12 +49,12 @@ public: return { (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none, ff_cap_none }; } - void rd_init(const QString& fname) override; + void rd_init(const QString& fname) override + {} void read() override; - void rd_deinit() override; - void wr_init(const QString& fname) override; + void wr_init(const QString& fname) override + {} void write() override; - void wr_deinit() override; private: @@ -66,7 +68,6 @@ private: char* deficon = nullptr; char* nuke_placer{}; - QString geo_fname; QVector geo_args = { {"deficon", &deficon, "Default icon name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr }, diff --git a/main.cc b/main.cc index 809e057f6..af61aa3e4 100644 --- a/main.cc +++ b/main.cc @@ -244,6 +244,57 @@ private: short_handle mkshort_handle; }; +static void +run_reader(Vecs::fmtinfo_t& ivecs, const QString& fname) +{ + start_session(ivecs.fmtname, fname); + if (ivecs.isDynamic()) { + ivecs.fmt = ivecs.factory(fname); + Vecs::init_vec(ivecs.fmt); + Vecs::prepare_format(ivecs); + + ivecs->rd_init(fname); + ivecs->read(); + ivecs->rd_deinit(); + + Vecs::exit_vec(ivecs.fmt); + delete ivecs.fmt; + ivecs.fmt = nullptr; + } else { + /* reinitialize xcsv in case two formats that use xcsv were given */ + Vecs::prepare_format(ivecs); + + ivecs->rd_init(fname); + ivecs->read(); + ivecs->rd_deinit(); + } +} + +static void +run_writer(Vecs::fmtinfo_t& ovecs, const QString& ofname) +{ + if (ovecs.isDynamic()) { + ovecs.fmt = ovecs.factory(ofname); + Vecs::init_vec(ovecs.fmt); + Vecs::prepare_format(ovecs); + + ovecs->wr_init(ofname); + ovecs->write(); + ovecs->wr_deinit(); + + Vecs::exit_vec(ovecs.fmt); + delete ovecs.fmt; + ovecs.fmt = nullptr; + } else { + /* reinitialize xcsv in case two formats that use xcsv were given */ + Vecs::prepare_format(ovecs); + + ovecs->wr_init(ofname); + ovecs->write(); + ovecs->wr_deinit(); + } +} + static int run(const char* prog_name) { @@ -342,10 +393,7 @@ run(const char* prog_name) global_opts.masked_objective |= WPTDATAMASK; } - start_session(ivecs.fmtname, fname); - ivecs->rd_init(fname); - ivecs->read(); - ivecs->rd_deinit(); + run_reader(ivecs, fname); did_something = true; break; @@ -361,9 +409,7 @@ run(const char* prog_name) global_opts.masked_objective |= WPTDATAMASK; } - ovecs->wr_init(ofname); - ovecs->write(); - ovecs->wr_deinit(); + run_writer(ovecs, ofname); } break; @@ -532,21 +578,11 @@ run(const char* prog_name) global_opts.masked_objective |= WPTDATAMASK; } - /* reinitialize xcsv in case two formats that use xcsv were given */ - Vecs::Instance().prepare_format(ivecs); - - start_session(ivecs.fmtname, qargs.at(0)); - ivecs->rd_init(qargs.at(0)); - ivecs->read(); - ivecs->rd_deinit(); + run_reader(ivecs, qargs.at(0)); if (qargs.size() == 2 && ovecs) { - /* reinitialize xcsv in case two formats that use xcsv were given */ - Vecs::Instance().prepare_format(ovecs); - ovecs->wr_init(qargs.at(1)); - ovecs->write(); - ovecs->wr_deinit(); + run_writer(ovecs, qargs.at(1)); } } else if (!qargs.isEmpty()) { @@ -576,7 +612,18 @@ run(const char* prog_name) if (fname.isEmpty()) { fatal("An input file (-f) must be specified.\n"); } + + if (ivecs.isDynamic()) { + ivecs.fmt = ivecs.factory(fname); + Vecs::init_vec(ivecs.fmt); + } + if (ovecs && ovecs.isDynamic()) { + ovecs.fmt = ovecs.factory(ofname); + Vecs::init_vec(ovecs.fmt); + } + start_session(ivecs.fmtname, fname); + Vecs::prepare_format(ivecs); ivecs->rd_position_init(fname); if (global_opts.masked_objective & ~POSNDATAMASK) { @@ -588,6 +635,7 @@ run(const char* prog_name) } if (ovecs) { + Vecs::prepare_format(ovecs); ovecs->wr_position_init(ofname); } @@ -611,10 +659,23 @@ run(const char* prog_name) delete wpt; } } + Vecs::prepare_format(ivecs); ivecs->rd_position_deinit(); if (ovecs) { + Vecs::prepare_format(ovecs); ovecs->wr_position_deinit(); } + + if (ovecs && ovecs.isDynamic()) { + Vecs::exit_vec(ovecs.fmt); + delete ovecs.fmt; + ovecs.fmt = nullptr; + } + if (ivecs.isDynamic()) { + Vecs::exit_vec(ivecs.fmt); + delete ivecs.fmt; + ivecs.fmt = nullptr; + } return 0; } diff --git a/reference/track/iblue747~csv.csv b/reference/track/iblue747~csv.csv new file mode 100644 index 000000000..1ba0a399a --- /dev/null +++ b/reference/track/iblue747~csv.csv @@ -0,0 +1,747 @@ +51.31177, 12.41318, +51.31181, 12.41290, +51.31188, 12.41277, +51.31216, 12.41226, +51.31224, 12.41238, +51.31225, 12.41242, +51.31229, 12.41249, +51.31263, 12.41285, +51.31272, 12.41282, +51.31281, 12.41274, +51.31281, 12.41272, +51.31274, 12.41275, +51.31272, 12.41270, +51.31276, 12.41279, +51.31285, 12.41296, +51.31296, 12.41307, +51.31305, 12.41318, +51.31309, 12.41302, +51.31298, 12.41302, +51.31301, 12.41301, +51.31299, 12.41297, +51.31302, 12.41302, +51.31298, 12.41320, +51.31306, 12.41312, +51.31298, 12.41302, +51.31290, 12.41297, +51.31285, 12.41296, +51.31280, 12.41294, +51.31250, 12.41312, +51.31246, 12.41288, +51.31275, 12.41253, +51.31296, 12.41317, +51.31288, 12.41324, +51.31286, 12.41324, +51.31282, 12.41331, +51.31284, 12.41328, +51.31283, 12.41331, +51.31279, 12.41334, +51.31278, 12.41333, +51.31276, 12.41334, +51.31282, 12.41332, +51.31292, 12.41344, +51.31299, 12.41379, +51.31304, 12.41381, +51.31305, 12.41384, +51.31311, 12.41385, +51.31321, 12.41388, +51.31329, 12.41397, +51.31329, 12.41405, +51.31327, 12.41410, +51.31304, 12.41461, +51.31298, 12.41483, +51.31293, 12.41494, +51.31295, 12.41497, +51.31293, 12.41498, +51.31296, 12.41495, +51.31317, 12.41459, +51.31317, 12.41457, +51.31316, 12.41444, +51.31316, 12.41439, +51.31334, 12.41391, +51.31371, 12.41332, +51.31399, 12.41286, +51.31422, 12.41249, +51.31465, 12.40956, +51.31465, 12.40949, +51.31465, 12.40949, +51.31465, 12.40945, +51.31464, 12.40936, +51.31464, 12.40936, +51.31464, 12.40936, +51.31464, 12.40936, +51.31464, 12.40936, +51.31512, 12.41022, +51.31517, 12.41034, +51.31509, 12.41022, +51.31506, 12.41031, +51.31496, 12.41036, +51.31485, 12.40939, +51.31484, 12.40938, +51.31484, 12.40945, +51.31486, 12.40930, +51.31412, 12.40669, +51.31396, 12.40623, +51.31370, 12.40579, +51.31334, 12.40497, +51.31270, 12.40350, +51.31221, 12.40235, +51.31185, 12.40145, +51.31140, 12.40011, +51.31101, 12.39885, +51.31066, 12.39779, +51.31050, 12.39728, +51.31043, 12.39698, +51.30961, 12.39358, +51.30946, 12.39236, +51.30931, 12.39060, +51.30924, 12.38872, +51.30928, 12.38751, +51.30943, 12.38620, +51.30962, 12.38478, +51.30985, 12.38313, +51.31010, 12.38143, +51.31024, 12.38029, +51.31027, 12.37932, +51.31032, 12.37870, +51.31038, 12.37778, +51.31048, 12.37646, +51.31060, 12.37526, +51.31068, 12.37448, +51.31072, 12.37411, +51.30883, 12.37343, +51.30854, 12.37345, +51.30777, 12.37349, +51.30718, 12.37357, +51.30658, 12.37362, +51.30542, 12.37378, +51.30472, 12.37395, +51.30380, 12.37424, +51.30322, 12.37419, +51.30267, 12.37387, +51.30224, 12.37362, +51.30188, 12.37324, +51.30178, 12.37309, +51.30161, 12.37265, +51.30170, 12.37224, +51.30179, 12.37179, +51.30206, 12.37150, +51.30223, 12.37154, +51.30242, 12.37171, +51.30243, 12.37208, +51.30226, 12.37251, +51.30161, 12.37379, +51.30097, 12.37475, +51.30044, 12.37540, +51.29965, 12.37603, +51.29877, 12.37646, +51.29787, 12.37656, +51.29688, 12.37664, +51.29528, 12.37674, +51.29335, 12.37755, +51.29225, 12.37790, +51.29114, 12.37803, +51.28943, 12.37808, +51.28728, 12.37854, +51.28639, 12.37917, +51.28505, 12.38029, +51.28343, 12.38171, +51.28219, 12.38266, +51.28127, 12.38312, +51.28032, 12.38329, +51.27890, 12.38341, +51.27738, 12.38336, +51.27595, 12.38314, +51.27460, 12.38279, +51.27271, 12.38222, +51.27198, 12.38200, +51.27083, 12.38165, +51.26981, 12.38146, +51.26827, 12.38132, +51.26680, 12.38136, +51.26530, 12.38163, +51.26381, 12.38204, +51.26292, 12.38230, +51.26111, 12.38289, +51.26060, 12.38306, +51.25979, 12.38326, +51.25847, 12.38358, +51.25635, 12.38404, +51.25462, 12.38438, +51.25299, 12.38462, +51.25178, 12.38484, +51.25046, 12.38514, +51.24874, 12.38572, +51.24735, 12.38627, +51.24566, 12.38703, +51.24378, 12.38776, +51.24205, 12.38833, +51.24094, 12.38848, +51.24035, 12.38856, +51.23932, 12.38862, +51.23828, 12.38861, +51.23688, 12.38859, +51.23538, 12.38857, +51.23290, 12.38852, +51.23119, 12.38835, +51.23028, 12.38822, +51.22924, 12.38808, +51.22801, 12.38798, +51.22402, 12.38775, +51.22241, 12.38767, +51.22061, 12.38760, +51.21923, 12.38760, +51.21784, 12.38787, +51.21672, 12.38832, +51.21544, 12.38914, +51.21442, 12.39003, +51.21347, 12.39113, +51.21263, 12.39234, +51.21179, 12.39392, +51.21103, 12.39570, +51.20998, 12.39856, +51.20837, 12.40303, +51.20728, 12.40607, +51.20622, 12.40904, +51.20511, 12.41198, +51.20408, 12.41444, +51.20304, 12.41667, +51.20178, 12.41929, +51.20052, 12.42208, +51.20007, 12.42366, +51.19955, 12.42597, +51.19889, 12.42878, +51.19794, 12.43220, +51.19710, 12.43514, +51.19641, 12.43786, +51.19613, 12.43967, +51.19604, 12.44114, +51.19611, 12.44297, +51.19629, 12.44543, +51.19652, 12.44853, +51.19649, 12.45027, +51.19624, 12.45172, +51.19587, 12.45351, +51.19534, 12.45619, +51.19509, 12.45764, +51.19467, 12.46005, +51.19422, 12.46184, +51.19378, 12.46312, +51.19322, 12.46464, +51.19259, 12.46635, +51.19206, 12.46768, +51.19129, 12.46952, +51.19051, 12.47131, +51.18976, 12.47302, +51.18881, 12.47520, +51.18831, 12.47632, +51.18772, 12.47736, +51.18722, 12.47796, +51.18630, 12.47869, +51.18520, 12.47960, +51.18455, 12.48015, +51.18388, 12.48072, +51.18320, 12.48129, +51.18213, 12.48221, +51.18114, 12.48306, +51.18011, 12.48393, +51.17862, 12.48528, +51.17711, 12.48665, +51.17544, 12.48820, +51.17471, 12.48888, +51.17336, 12.49012, +51.17185, 12.49153, +51.17009, 12.49316, +51.16809, 12.49501, +51.16676, 12.49625, +51.16529, 12.49762, +51.16389, 12.49892, +51.16195, 12.50074, +51.15981, 12.50286, +51.15812, 12.50470, +51.15636, 12.50680, +51.15567, 12.50746, +51.15507, 12.50786, +51.15428, 12.50815, +51.15340, 12.50844, +51.15246, 12.50872, +51.15185, 12.50891, +51.15115, 12.50915, +51.15013, 12.50946, +51.14901, 12.50965, +51.14794, 12.50969, +51.14700, 12.50972, +51.14537, 12.50987, +51.14380, 12.50999, +51.14265, 12.51008, +51.14102, 12.51003, +51.14007, 12.50992, +51.13942, 12.50984, +51.13862, 12.50975, +51.13799, 12.50955, +51.13772, 12.50943, +51.13750, 12.50929, +51.13739, 12.50922, +51.13694, 12.50894, +51.13682, 12.50886, +51.13608, 12.50837, +51.13550, 12.50798, +51.13441, 12.50725, +51.13326, 12.50647, +51.13245, 12.50600, +51.13152, 12.50563, +51.13032, 12.50517, +51.12969, 12.50497, +51.12894, 12.50471, +51.12822, 12.50450, +51.12693, 12.50178, +51.12656, 12.50063, +51.12630, 12.49978, +51.12614, 12.49874, +51.12601, 12.49745, +51.12578, 12.49588, +51.12546, 12.49462, +51.12506, 12.49352, +51.12446, 12.49225, +51.12382, 12.49121, +51.12281, 12.48996, +51.12245, 12.48951, +51.12201, 12.48900, +51.12141, 12.48836, +51.12105, 12.48797, +51.12077, 12.48739, +51.12072, 12.48720, +51.12029, 12.48563, +51.11970, 12.48428, +51.11935, 12.48401, +51.11906, 12.48407, +51.11886, 12.48418, +51.11790, 12.48487, +51.11742, 12.48522, +51.11675, 12.48575, +51.11627, 12.48616, +51.11543, 12.48687, +51.11463, 12.48756, +51.11371, 12.48825, +51.11333, 12.48853, +51.11301, 12.48877, +51.11276, 12.48896, +51.11248, 12.48917, +51.11212, 12.48957, +51.11156, 12.49029, +51.11097, 12.49098, +51.11060, 12.49114, +51.11046, 12.49116, +51.10966, 12.49109, +51.10883, 12.49082, +51.10813, 12.49034, +51.10742, 12.48967, +51.10680, 12.48888, +51.10606, 12.48784, +51.10529, 12.48676, +51.10461, 12.48581, +51.10361, 12.48441, +51.10273, 12.48302, +51.10208, 12.48161, +51.10131, 12.47986, +51.10064, 12.47888, +51.09990, 12.47809, +51.09887, 12.47730, +51.09691, 12.47601, +51.09526, 12.47491, +51.09426, 12.47418, +51.09345, 12.47320, +51.09260, 12.47237, +51.09185, 12.47178, +51.09107, 12.47117, +51.09021, 12.47046, +51.08925, 12.46975, +51.08836, 12.46926, +51.08718, 12.46866, +51.08609, 12.46826, +51.08453, 12.46767, +51.08360, 12.46700, +51.08170, 12.46562, +51.08137, 12.46543, +51.08043, 12.46511, +51.07919, 12.46482, +51.07797, 12.46453, +51.07690, 12.46425, +51.07575, 12.46396, +51.07501, 12.46359, +51.07438, 12.46310, +51.07392, 12.46250, +51.07331, 12.46164, +51.07288, 12.46106, +51.07242, 12.46039, +51.07172, 12.45942, +51.07029, 12.45744, +51.06939, 12.45619, +51.06787, 12.45409, +51.06758, 12.45381, +51.06701, 12.45350, +51.06672, 12.45348, +51.06579, 12.45346, +51.06486, 12.45355, +51.06436, 12.45375, +51.06362, 12.45399, +51.06280, 12.45405, +51.06258, 12.45406, +51.06215, 12.45384, +51.06178, 12.45348, +51.06146, 12.45347, +51.06134, 12.45352, +51.06047, 12.45388, +51.05968, 12.45420, +51.05830, 12.45477, +51.05796, 12.45488, +51.05727, 12.45477, +51.05630, 12.45439, +51.05493, 12.45386, +51.05454, 12.45372, +51.05403, 12.45349, +51.05338, 12.45317, +51.05332, 12.45316, +51.05292, 12.45322, +51.05190, 12.45364, +51.05060, 12.45420, +51.04975, 12.45444, +51.04888, 12.45471, +51.04741, 12.45519, +51.04662, 12.45540, +51.04585, 12.45539, +51.04422, 12.45532, +51.04308, 12.45536, +51.04232, 12.45568, +51.04161, 12.45632, +51.04058, 12.45735, +51.03970, 12.45789, +51.03872, 12.45824, +51.03732, 12.45865, +51.03579, 12.45888, +51.03481, 12.45888, +51.03388, 12.45861, +51.03243, 12.45809, +51.03149, 12.45800, +51.02979, 12.45810, +51.02916, 12.45811, +51.02856, 12.45809, +51.02759, 12.45810, +51.02663, 12.45809, +51.02572, 12.45786, +51.02479, 12.45750, +51.02387, 12.45689, +51.02193, 12.45524, +51.02099, 12.45475, +51.02003, 12.45462, +51.01878, 12.45447, +51.01789, 12.45437, +51.01689, 12.45425, +51.01572, 12.45412, +51.01468, 12.45400, +51.01351, 12.45401, +51.01261, 12.45425, +51.01166, 12.45473, +51.01079, 12.45543, +51.01000, 12.45641, +51.00914, 12.45752, +51.00788, 12.45894, +51.00639, 12.46046, +51.00569, 12.46139, +51.00515, 12.46239, +51.00455, 12.46373, +51.00349, 12.46626, +51.00280, 12.46756, +51.00200, 12.46865, +51.00113, 12.46955, +51.00010, 12.47027, +50.99898, 12.47072, +50.99813, 12.47089, +50.99709, 12.47091, +50.99606, 12.47064, +50.99497, 12.47020, +50.99298, 12.46923, +50.99114, 12.46834, +50.98960, 12.46759, +50.98795, 12.46679, +50.98599, 12.46599, +50.98478, 12.46568, +50.98336, 12.46564, +50.98183, 12.46559, +50.98029, 12.46536, +50.97898, 12.46487, +50.97768, 12.46409, +50.97651, 12.46313, +50.97544, 12.46200, +50.97445, 12.46063, +50.97356, 12.45901, +50.97278, 12.45729, +50.97154, 12.45396, +50.97015, 12.45028, +50.96886, 12.44684, +50.96773, 12.44382, +50.96609, 12.43942, +50.96487, 12.43614, +50.96441, 12.43462, +50.96408, 12.43325, +50.96368, 12.43120, +50.96339, 12.42902, +50.96312, 12.42697, +50.96269, 12.42394, +50.96221, 12.42166, +50.96158, 12.41949, +50.96086, 12.41767, +50.96003, 12.41584, +50.95911, 12.41416, +50.95835, 12.41302, +50.95763, 12.41208, +50.95670, 12.41101, +50.95561, 12.41004, +50.95454, 12.40919, +50.95298, 12.40808, +50.95177, 12.40728, +50.95030, 12.40625, +50.94977, 12.40583, +50.94880, 12.40501, +50.94818, 12.40448, +50.94725, 12.40368, +50.94652, 12.40305, +50.94566, 12.40232, +50.94452, 12.40138, +50.94389, 12.40086, +50.94268, 12.39994, +50.94166, 12.39920, +50.94114, 12.39902, +50.94116, 12.39911, +50.94148, 12.39995, +50.94205, 12.40134, +50.94238, 12.40234, +50.94258, 12.40331, +50.94270, 12.40416, +50.94284, 12.40604, +50.94295, 12.40750, +50.94289, 12.40862, +50.94282, 12.41003, +50.94280, 12.41110, +50.94276, 12.41193, +50.94270, 12.41220, +50.94248, 12.41254, +50.94172, 12.41331, +50.94120, 12.41378, +50.94091, 12.41392, +50.94049, 12.41396, +50.94017, 12.41403, +50.93989, 12.41409, +50.93948, 12.41441, +50.93908, 12.41473, +50.93859, 12.41478, +50.93795, 12.41471, +50.93730, 12.41467, +50.93648, 12.41495, +50.93597, 12.41516, +50.93535, 12.41545, +50.93492, 12.41583, +50.93448, 12.41640, +50.93441, 12.41649, +50.93396, 12.41687, +50.93372, 12.41728, +50.93370, 12.41752, +50.93367, 12.41811, +50.93368, 12.41818, +50.93373, 12.41847, +50.93378, 12.41880, +50.93375, 12.41929, +50.93373, 12.41937, +50.93359, 12.41977, +50.93331, 12.42035, +50.93312, 12.42074, +50.93309, 12.42075, +50.93289, 12.42087, +50.93231, 12.42119, +50.93179, 12.42153, +50.93146, 12.42193, +50.93111, 12.42231, +50.93065, 12.42248, +50.93057, 12.42248, +50.93021, 12.42231, +50.93013, 12.42227, +50.92986, 12.42243, +50.92969, 12.42273, +50.92943, 12.42347, +50.92898, 12.42415, +50.92869, 12.42456, +50.92838, 12.42498, +50.92810, 12.42539, +50.92743, 12.42637, +50.92732, 12.42654, +50.92714, 12.42657, +50.92711, 12.42657, +50.92688, 12.42664, +50.92677, 12.42696, +50.92649, 12.42758, +50.92603, 12.42820, +50.92523, 12.42912, +50.92435, 12.43008, +50.92374, 12.43058, +50.92326, 12.43098, +50.92292, 12.43125, +50.92262, 12.43150, +50.92218, 12.43201, +50.92196, 12.43229, +50.92186, 12.43241, +50.92181, 12.43263, +50.92190, 12.43281, +50.92216, 12.43338, +50.92235, 12.43440, +50.92236, 12.43454, +50.92242, 12.43524, +50.92245, 12.43580, +50.92241, 12.43635, +50.92228, 12.43684, +50.92213, 12.43764, +50.92210, 12.43856, +50.92210, 12.43897, +50.92197, 12.43961, +50.92189, 12.43973, +50.92133, 12.44067, +50.92090, 12.44099, +50.92061, 12.44111, +50.92019, 12.44160, +50.92009, 12.44210, +50.92009, 12.44231, +50.92013, 12.44295, +50.92021, 12.44361, +50.92021, 12.44414, +50.92014, 12.44459, +50.92009, 12.44496, +50.91991, 12.44493, +50.91939, 12.44478, +50.91881, 12.44461, +50.91795, 12.44436, +50.91728, 12.44416, +50.91625, 12.44385, +50.91494, 12.44347, +50.91432, 12.44328, +50.91345, 12.44303, +50.91240, 12.44271, +50.91163, 12.44253, +50.91119, 12.44245, +50.91085, 12.44223, +50.91050, 12.44187, +50.91008, 12.44164, +50.90939, 12.44138, +50.90855, 12.44106, +50.90763, 12.44073, +50.90686, 12.44045, +50.90550, 12.43996, +50.90494, 12.44001, +50.90390, 12.44021, +50.90279, 12.44043, +50.90157, 12.44073, +50.90086, 12.44077, +50.90012, 12.44047, +50.89959, 12.44005, +50.89912, 12.43932, +50.89875, 12.43875, +50.89830, 12.43820, +50.89739, 12.43721, +50.89642, 12.43616, +50.89566, 12.43536, +50.89516, 12.43498, +50.89432, 12.43453, +50.89349, 12.43410, +50.89271, 12.43371, +50.89191, 12.43344, +50.89107, 12.43352, +50.89058, 12.43357, +50.89023, 12.43362, +50.88976, 12.43370, +50.88908, 12.43386, +50.88864, 12.43399, +50.88850, 12.43378, +50.88849, 12.43367, +50.88836, 12.43254, +50.88834, 12.43240, +50.88824, 12.43202, +50.88780, 12.43101, +50.88753, 12.43078, +50.88726, 12.43086, +50.88671, 12.43103, +50.88612, 12.43096, +50.88539, 12.43067, +50.88531, 12.43065, +50.88507, 12.43064, +50.88454, 12.43036, +50.88417, 12.43014, +50.88369, 12.43012, +50.88323, 12.43046, +50.88294, 12.43066, +50.88220, 12.43101, +50.88210, 12.43108, +50.88155, 12.43163, +50.88090, 12.43223, +50.88027, 12.43262, +50.87958, 12.43292, +50.87884, 12.43323, +50.87812, 12.43355, +50.87732, 12.43390, +50.87664, 12.43432, +50.87581, 12.43486, +50.87536, 12.43516, +50.87470, 12.43513, +50.87404, 12.43503, +50.87316, 12.43481, +50.87260, 12.43466, +50.87216, 12.43434, +50.87206, 12.43421, +50.87135, 12.43340, +50.87061, 12.43275, +50.86996, 12.43206, +50.86941, 12.43147, +50.86822, 12.43046, +50.86718, 12.42966, +50.86636, 12.42927, +50.86571, 12.42912, +50.86482, 12.42906, +50.86414, 12.42902, +50.86351, 12.42868, +50.86246, 12.42812, +50.86172, 12.42779, +50.86097, 12.42736, +50.86039, 12.42687, +50.85994, 12.42654, +50.85980, 12.42648, +50.85949, 12.42649, +50.85917, 12.42658, +50.85879, 12.42640, +50.85872, 12.42619, +50.85853, 12.42520, +50.85847, 12.42485, +50.85831, 12.42450, +50.85804, 12.42447, +50.85794, 12.42424, +50.85794, 12.42377, +50.85799, 12.42333, +50.85811, 12.42258, +50.85822, 12.42165, +50.85817, 12.42106, +50.85804, 12.42088, +50.85768, 12.42042, +50.85765, 12.42036, +50.85750, 12.41992, +50.85747, 12.41912, +50.85748, 12.41859, +50.85749, 12.41841, +50.85750, 12.41818, +50.85751, 12.41791, +50.85751, 12.41780, +50.85771, 12.41791, +50.85771, 12.41796, +50.85771, 12.41797, +50.85779, 12.41793, +50.85772, 12.41785, +50.85778, 12.41797, +50.85770, 12.41784, +50.85777, 12.41791, +50.85778, 12.41794, +50.85778, 12.41796, diff --git a/testo.d/geo.test b/testo.d/geo.test index 1bd748d19..13aa45d6c 100644 --- a/testo.d/geo.test +++ b/testo.d/geo.test @@ -4,6 +4,11 @@ rm -f ${TMPDIR}/gl.loc gpsbabel -i geo -f ${REFERENCE}/geocaching.loc -o geo -F ${TMPDIR}/gl.loc compare ${TMPDIR}/gl.loc ${REFERENCE} +# try with positional arugments +rm -f ${TMPDIR}/gl.loc +gpsbabel -i geo -o geo ${REFERENCE}/geocaching.loc ${TMPDIR}/gl.loc +compare ${TMPDIR}/gl.loc ${REFERENCE} + # we have a one off reader in geo, make sure it can read stdin. rm -f ${TMPDIR}/gl_si.loc cat ${REFERENCE}/geocaching.loc | gpsbabel -i geo -f - -o geo -F ${TMPDIR}/gl_si.loc diff --git a/testo.d/iblue747.test b/testo.d/iblue747.test index 03d5c3e49..c7d543484 100644 --- a/testo.d/iblue747.test +++ b/testo.d/iblue747.test @@ -4,3 +4,6 @@ gpsbabel -i iblue747 -f ${REFERENCE}/track/iblue747.csv -o gpx -F ${TMPDIR}/iblue747~csv.gpx compare ${REFERENCE}/track/iblue747~csv.gpx ${TMPDIR}/iblue747~csv.gpx +gpsbabel -i iblue747 -o csv -f ${REFERENCE}/track/iblue747.csv -F ${TMPDIR}/iblue747~csv.csv +compare ${REFERENCE}/track/iblue747~csv.csv ${TMPDIR}/iblue747~csv.csv + diff --git a/vecs.cc b/vecs.cc index 9ac40b44a..a48a380aa 100644 --- a/vecs.cc +++ b/vecs.cc @@ -36,6 +36,7 @@ #include // for sort #include // for assert #include // for printf, putchar, sscanf +#include // for add_const<>::type, is_base_of #include "defs.h" // for arglist_t, ff_vecs_t, ff_cap, fatal, CSTR, ARGTYPE_TYPEMASK, case_ignore_strcmp, global_options, global_opts, warning, xfree, ARGTYPE_BOOL, ff_cap_read, ff_cap_write, ARGTYPE_HIDDEN, ff_type_internal, xstrdup, ARGTYPE_INT, ARGTYPE_REQUIRED, ARGTYPE_FLOAT #include "dg-100.h" // for Dg100FileFormat, Dg100SerialFormat, Dg200FileFormat, Dg200SerialFormat @@ -105,6 +106,13 @@ extern ff_vecs_t format_garmin_xt_vecs; #define MYNAME "vecs" +template +Format* fmtfactory(const QString& filename) +{ + static_assert(std::is_base_of::value, "T must be derived from Format"); + return new T(filename); +} + struct Vecs::Impl { /* * Having these LegacyFormat instances be non-static data members @@ -113,10 +121,6 @@ struct Vecs::Impl { * instance is guaranteed to have already constructed when an instance * of this class is constructed. */ -#if CSVFMTS_ENABLED - XcsvFormat xcsv_fmt; -#endif // CSVFMTS_ENABLED - GeoFormat geo_fmt; GpxFormat gpx_fmt; LegacyFormat garmin_fmt {garmin_vecs}; GdbFormat gdb_fmt; @@ -182,19 +186,21 @@ struct Vecs::Impl { #if CSVFMTS_ENABLED /* XCSV must be the first entry in this table. */ { - &xcsv_fmt, + nullptr, "xcsv", "? Character Separated Values", nullptr, nullptr, + &fmtfactory }, #endif { - &geo_fmt, + nullptr, "geo", "Geocaching.com .loc", "loc", nullptr, + &fmtfactory }, { &gpx_fmt, @@ -595,18 +601,25 @@ Vecs& Vecs::Instance() * the default the default constructor would be implicitly deleted. */ +void Vecs::init_vec(Format* fmt) +{ + QVector* args = fmt->get_args(); + if (args && !args->isEmpty()) { + assert(args->isDetached()); + for (auto& arg : *args) { + arg.argvalptr = nullptr; + if (arg.argval) { + *arg.argval = nullptr; + } + } + } +} + void Vecs::init_vecs() { for (const auto& vec : d_ptr_->vec_list) { - QVector* args = vec.vec->get_args(); - if (args && !args->isEmpty()) { - assert(args->isDetached()); - for (auto& arg : *args) { - arg.argvalptr = nullptr; - if (arg.argval) { - *arg.argval = nullptr; - } - } + if (vec.vec != nullptr) { + init_vec(vec.vec); } } style_list = create_style_vec(); @@ -672,19 +685,26 @@ bool Vecs::is_bool(const QString& val) (!val.isEmpty() && val.at(0).isDigit()); } +void Vecs::exit_vec(Format* fmt) +{ + (fmt->exit)(); + QVector* args = fmt->get_args(); + if (args && !args->isEmpty()) { + assert(args->isDetached()); + for (auto& arg : *args) { + if (arg.argvalptr) { + xfree(arg.argvalptr); + *arg.argval = arg.argvalptr = nullptr; + } + } + } +} + void Vecs::exit_vecs() { for (const auto& vec : d_ptr_->vec_list) { - (vec.vec->exit)(); - QVector* args = vec.vec->get_args(); - if (args && !args->isEmpty()) { - assert(args->isDetached()); - for (auto& arg : *args) { - if (arg.argvalptr) { - xfree(arg.argvalptr); - *arg.argval = arg.argvalptr = nullptr; - } - } + if (vec.vec != nullptr) { + exit_vec(vec.vec); } } style_list.clear(); @@ -799,7 +819,7 @@ void Vecs::validate_options(const QStringList& options, const QVector } } -void Vecs::prepare_format(const fmtinfo_t& fmtdata) const +void Vecs::prepare_format(const fmtinfo_t& fmtdata) { QVector* args = fmtdata->get_args(); @@ -838,7 +858,10 @@ void Vecs::prepare_format(const fmtinfo_t& fmtdata) const * that we are processing xcsv,style= and it was preceeded by an xcsv * format that utilized an internal style file. */ - d_ptr_->xcsv_fmt.xcsv_setup_internal_style(fmtdata.style_filename); + auto* xcsvfmt = dynamic_cast(fmtdata.fmt); + if (xcsvfmt != nullptr) { + xcsvfmt->xcsv_setup_internal_style(fmtdata.style_filename); + } #endif // CSVFMTS_ENABLED } @@ -855,9 +878,7 @@ Vecs::fmtinfo_t Vecs::find_vec(const QString& fmtargstring) continue; } - fmtinfo_t fmtinfo{vec.vec, vec.name, nullptr, options}; - prepare_format(fmtinfo); - return fmtinfo; + return {vec.vec, vec.name, nullptr, options, vec.factory}; } /* @@ -869,9 +890,7 @@ Vecs::fmtinfo_t Vecs::find_vec(const QString& fmtargstring) continue; } - fmtinfo_t fmtinfo{d_ptr_->vec_list.at(0).vec, svec.name, svec.style_filename, options}; - prepare_format(fmtinfo); - return fmtinfo; + return {d_ptr_->vec_list.at(0).vec, svec.name, svec.style_filename, options, d_ptr_->vec_list.at(0).factory}; } /* @@ -948,6 +967,7 @@ QVector Vecs::sort_and_unify_vecs() const /* Gather relevant information for normal formats. */ for (const auto& vec : d_ptr_->vec_list) { + Format* fmt = (vec.factory != nullptr)? vec.factory("") : vec.vec; vecinfo_t info; info.name = vec.name; info.desc = vec.desc; @@ -957,15 +977,18 @@ QVector Vecs::sort_and_unify_vecs() const } else { info.parent = vec.parent; } - info.type = vec.vec->get_type(); - info.cap = vec.vec->get_cap(); - const QVector* args = vec.vec->get_args(); + info.type = fmt->get_type(); + info.cap = fmt->get_cap(); + const QVector* args = fmt->get_args(); if (args != nullptr) { for (const auto& arg : *args) { info.arginfo.append(arginfo_t(arg)); } } svp.append(info); + if (vec.factory != nullptr) { + delete fmt; + } } #if CSVFMTS_ENABLED @@ -973,11 +996,13 @@ QVector Vecs::sort_and_unify_vecs() const * Make sure we know which entry in the vector list that is. */ assert(d_ptr_->vec_list.at(0).name.compare("xcsv", Qt::CaseInsensitive) == 0); + + Format* xcsvfmt = (d_ptr_->vec_list.at(0).factory != nullptr)? d_ptr_->vec_list.at(0).factory("") : d_ptr_->vec_list.at(0).vec; /* The style formats use a modified xcsv argument list that doesn't include * the option to set the style file. Make sure we know which entry in * the argument list that is. */ - assert(case_ignore_strcmp(d_ptr_->vec_list.at(0).vec->get_args()->at(0).helpstring, + assert(case_ignore_strcmp(xcsvfmt->get_args()->at(0).helpstring, "Full path to XCSV style file") == 0); /* Gather the relevant info for the style based formats. */ @@ -1009,7 +1034,7 @@ QVector Vecs::sort_and_unify_vecs() const * 'Full path to XCSV style file' argument to any * GUIs for an internal format. */ - const QVector* args = d_ptr_->vec_list.at(0).vec->get_args(); + const QVector* args = xcsvfmt->get_args(); if (args != nullptr) { bool first = true; for (const auto& arg : *args) { @@ -1021,6 +1046,9 @@ QVector Vecs::sort_and_unify_vecs() const } svp.append(info); } + if (d_ptr_->vec_list.at(0).factory != nullptr) { + delete xcsvfmt; + } #endif // CSVFMTS_ENABLED /* @@ -1276,7 +1304,11 @@ bool Vecs::validate_args(const QString& name, const QVector* args) bool Vecs::validate_vec(const vecs_t& vec) { - bool ok = validate_args(vec.name, vec.vec->get_args()); + Format* fmt = (vec.factory != nullptr)? vec.factory("") : vec.vec; + bool ok = validate_args(vec.name, fmt->get_args()); + if (vec.factory != nullptr) { + delete fmt; + } return ok; } diff --git a/vecs.h b/vecs.h index dc9193cc1..fcb15ee65 100644 --- a/vecs.h +++ b/vecs.h @@ -21,11 +21,12 @@ #ifndef VECS_H_INCLUDED_ #define VECS_H_INCLUDED_ -#include // for uint32_t +#include // for uint32_t -#include // for QString -#include // for QStringList -#include // for QVector<>::iterator, QVector +#include // for QList +#include // for QString +#include // for QStringList +#include // for QVector<>::iterator, QVector #include "defs.h" #include "format.h" @@ -38,20 +39,26 @@ public: /* Types */ + using FormatFactory = Format* (*)(const QString&); + class fmtinfo_t { public: + bool isDynamic() { + return factory != nullptr; + } explicit operator bool() const { - return fmt != nullptr; + return ((fmt != nullptr) || (factory != nullptr)); } Format* operator->() const { return fmt; } - Format* fmt{}; + Format* fmt{nullptr}; QString fmtname; QString style_filename; QStringList options; + FormatFactory factory{nullptr}; }; /* Special Member Functions */ @@ -64,13 +71,15 @@ public: /* Member Functions */ + static void init_vec(Format* fmt); void init_vecs(); + static void exit_vec(Format* fmt); void exit_vecs(); static void assign_option(const QString& module, arglist_t* arg, const QString& val); static void disp_vec_options(const QString& vecname, const QVector* args); static void validate_options(const QStringList& options, const QVector* args, const QString& name); static QString get_option(const QStringList& options, const QString& argname); - void prepare_format(const fmtinfo_t& data) const; + static void prepare_format(const fmtinfo_t& data) ; fmtinfo_t find_vec(const QString& fmtargstring); void disp_vecs() const; void disp_vec(const QString& vecname) const; @@ -90,6 +99,7 @@ private: QString desc; QString extensions; // list of possible extensions separated by '/', first is output default for GUI. QString parent; + FormatFactory factory{nullptr}; }; struct arginfo_t { diff --git a/xcsv.h b/xcsv.h index afa2711e4..97d581f79 100644 --- a/xcsv.h +++ b/xcsv.h @@ -262,6 +262,7 @@ private: class XcsvFormat : public Format { public: + using Format::Format; /* Member Functions */ QVector* get_args() override { -- 2.30.2